package com.lczyfz.istep.common.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;

public class FtpUtil {
    private static String FTP_BASE = PropertiesUtil.getProperty("FTP_BASE"); // ftp根目录
    private static Logger logger = LoggerFactory.getLogger(FtpUtil.class);
    /**
     * 本地字符编码
     */
    private static String LOCAL_CHARSET = "GBK";

    // FTP协议里面，规定文件名编码为iso-8859-1
    private static String SERVER_CHARSET = "ISO-8859-1";

    /**
     * FTP上传文件
     *
     * @param ip
     * @param port
     * @param username
     * @param password //* @param path
     *                 //* @param filename
     * @return
     */
    public static FTPClient getFtpClient(String ip, int port, String username, String password) {
        FTPClient ftp = new FTPClient();
        try {
            ftp.connect(ip, port);// 连接FTP服务器
            ftp.login(username, password);// 登录
            int reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
            }
            if (FTPReply.isPositiveCompletion(ftp.sendCommand(
                    "OPTS UTF8", "ON"))) {// 开启服务器对UTF-8的支持，如果服务器支持就用UTF-8编码，否则就使用本地编码（GBK）.
                LOCAL_CHARSET = "UTF-8";
            }

            ftp.enterLocalPassiveMode();
            ftp.setFileType(FTP.BINARY_FILE_TYPE, FTP.BINARY_FILE_TYPE);
            ftp.setFileTransferMode(FTP.BINARY_FILE_TYPE);
        } catch (SocketException e) {
            logger.error("连接ftp失败", e);
        } catch (IOException e) {
            logger.error("连接ftp失败", e);
        } catch (Exception e) {
            logger.error("连接FTP遇到未知错误", e);
        }
        return ftp;
    }

    public static InputStream download(FTPClient ftpClient, String filePath){
        InputStream inputStream = null;
        try {
            inputStream = ftpClient.retrieveFileStream(getServerString(FTP_BASE+filePath));
        } catch (Exception e){
            logger.error(e.getMessage(), e);
        }
        return inputStream;
    }

    public static boolean uploadFile(FTPClient ftpClient, String path, String filename, InputStream is) {
        boolean success = false;
        try {
            changeWorkingDirectoryByBasePath(ftpClient, path);
            success = ftpClient.storeFile(new String(filename.getBytes(LOCAL_CHARSET), SERVER_CHARSET), is);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (IOException e) {

            }
        }
        return success;
    }

    /**
     * @param source
     * @return
     * @author loser
     */
    private static String getServerString(String source) {
        try {
            return new String(source.getBytes(LOCAL_CHARSET), SERVER_CHARSET);
        } catch (UnsupportedEncodingException e) {
            logger.error("不支持的编码", e);
            return null;
        }
    }

    /**
     * @param source
     * @return
     * @author loser
     */
    private static String getLocalString(String source) {
        try {
            return new String(source.getBytes(SERVER_CHARSET),  LOCAL_CHARSET);
        } catch (UnsupportedEncodingException e) {
            logger.error("不支持的编码", e);
            return null;
        }
    }

    /**
     * @param ftpClient
     * @param path
     * @return
     * @author loser
     */
    public static boolean deleteDirectoryByBasePath(FTPClient ftpClient, String path) throws IOException {
        return deleteDirectory(ftpClient, FTP_BASE + path);
    }

    /**
     * @param ftpClient
     * @param path
     * @return
     * @author loser
     */
    private static boolean deleteDirectory(FTPClient ftpClient, String path) throws IOException {
        boolean success = false;
        logger.debug("listFiles:{}",ftpClient.listFiles(getServerString(path)));
        if(ftpClient.listFiles(getServerString(path))!=null)
        {
            for (FTPFile file : ftpClient.listFiles(getServerString(path))) {
                String filename = getLocalString(file.getName());
                if (filename.equals(".") || filename.equals("..")) {
                    continue;
                }

                if(file.isFile()){
                    if (!deleteFile(ftpClient, path + "/" + filename)) {
                        logger.debug("文件删除失败:{}",path + "/" + filename);
                        break;
                    }
                }else if(file.isDirectory()){
                    if( !deleteDirectory(ftpClient, path + "/" + filename) ){
                        logger.debug("文件夹删除失败:{}",path + "/" + filename);
                        break;
                    }
                }
            }
        }

        if (ftpClient.listFiles(getServerString(path)).length == 0 && ftpClient.removeDirectory(getServerString(path))) {
            success = true;
        }

        return success;
    }

    /**
     * @param ftpClient
     * @param path
     * @return
     * @author loser
     */
    public static boolean deleteFileByBasePath(FTPClient ftpClient, String path) throws IOException {
        return deleteFile(ftpClient, FTP_BASE + path);
    }

    /**
     * @param ftpClient
     * @param path
     * @return
     * @author loser
     */
    public static boolean deleteFile(FTPClient ftpClient, String path) throws IOException {
        boolean success = true;

        if (!ftpClient.deleteFile(getServerString(path))) {
            logger.error("删除文件 {} 失败!", path);
            success = false;
        }

        return success;
    }

    /**
     * @param ftpClient
     * @param path
     * @return
     * @author loser
     */
    public static boolean changeWorkingDirectoryByBasePath(FTPClient ftpClient, String path) throws IOException {
        return changeWorkingDirectory(ftpClient, FTP_BASE)
                && changeWorkingDirectoryByMakeDirectory(ftpClient, path);
    }

    /**
     * @param ftpClient
     * @param path
     * @return
     * @author loser
     */
    private static boolean changeWorkingDirectory(FTPClient ftpClient, String path) throws IOException {

        String targetPath = getServerString(path);
        if (!ftpClient.changeWorkingDirectory(targetPath)) {
            logger.error("切换至路径 {} 失败!", targetPath);
        }
        return true;
    }

    /**
     * @param ftpClient
     * @param path
     * @return
     * @author loser
     */
    private static boolean changeWorkingDirectoryByMakeDirectory(FTPClient ftpClient, String path) throws IOException {
        for (String dirName : StringUtils.split(path, '/')) {

            String targetDirName = getServerString(dirName);
            if (!ftpClient.changeWorkingDirectory(targetDirName)) {
                if (!ftpClient.makeDirectory(targetDirName) || !ftpClient.changeWorkingDirectory(targetDirName)) {
                    logger.error("路径 {} 中的目录 {} 进入失败!", path, dirName);
                    return false;
                }
            }
        }

        return true;
    }

    public static void closeFtp(FTPClient ftp) {
        try {
            if (ftp != null) {
                ftp.logout();
                ftp.disconnect();
            }
        } catch (IOException e) {
            logger.info("ftp断开连接出错", e);
        }
    }
}
